
/**
 * @fileoverview Dragger is responsible for scrolling,
 * dragging and easy shifting.
 *
 * @author honza.rychtar@gmail.com (Jan Rychtar)
*/


goog.provide('georeferencer.slider.Dragger');

goog.require('georeferencer.slider.Handler');
goog.require('goog.dom');
goog.require('goog.fx.Animation');
goog.require('goog.fx.Dragger.EventType');
goog.require('goog.fx.easing');
goog.require('goog.ui.Control');



/**
 * Creates new Dragger.
 * @param {!georeferencer.slider.Handler} Handler The instance of Handler.
 * @param {number=} opt_delay The duration of shifting (in miliseconds).
 * Defaults to 1300.
 * @constructor
 */
georeferencer.slider.Dragger = function(Handler, opt_delay) {

  /**
   * @type {number}
   * @private
   */
  this.dealy_ = goog.isDef(opt_delay) ? opt_delay : 1300;

  /**
   * @type {georeferencer.slider.Handler}
   * @private
   */
  this.Handler_ = Handler;

  this.shiftTimer_ = new goog.Timer(20);

  this.scrollTimer_ = new goog.Timer(200);

  this.setListeners_();
};


/**
 * Current mouse position (X coordinate).
 * @type {number}
 * @private
 */
georeferencer.slider.Dragger.prototype.XposNow_ = 0;


/**
 * Mouse position (X coordinate) at end of drag,
 * @type {number}
 * @private
 */
georeferencer.slider.Dragger.prototype.endDragPosX_ = 0;


/**
 * Mouse position (X coordinate) at dragging,
 * @type {number}
 * @private
 */
georeferencer.slider.Dragger.prototype.dragPosX_ = 0;


/**
 * @type {goog.fx.Dragger}
 * @private
 */
georeferencer.slider.Dragger.prototype.dragger_ = null;


/**
 * @type {goog.Timer}
 * @private
 */
georeferencer.slider.Dragger.prototype.shiftTimer_ = null;


/**
 * @type {goog.Timer}
 * @private
 */
georeferencer.slider.Dragger.prototype.scrollTimer_ = null;


/**
 * @type {boolean}
 */
georeferencer.slider.Dragger.prototype.dragging = false;


/**
 * @return {boolean} Returns true between start of dragging and
 * end of shifting, false otherwise.
 */
georeferencer.slider.Dragger.prototype.isDragging = function() {
  return this.dragging_;
};


/**
 * @private
 */
georeferencer.slider.Dragger.prototype.setListeners_ = function() {
  this.scrollTimer_.start();
  this.dragger_ = new goog.fx.Dragger(this.Handler_.getDraggingArea());
  this.dragger_.addEventListener(
    goog.fx.Dragger.EventType.DRAG, this.onDrag_, false, this);
  this.dragger_.addEventListener(
    goog.fx.Dragger.EventType.START, this.onDragStart_, false, this);
  this.dragger_.addEventListener(
    goog.fx.Dragger.EventType.END, this.onDragEnd_, false, this);  
    
  goog.events.listen(this.shiftTimer_, goog.Timer.TICK,
    this.onShiftTick_, false, this);
  goog.events.listen(this.Handler_.getDraggingArea(),
    goog.events.EventType.MOUSEMOVE,
    this.onMouseMove_, false, this);
  goog.events.listen(this.Handler_.getDraggingArea(),
    goog.events.EventType.MOUSEDOWN,
    this.onMouseDown_, false, this);
  goog.events.listen(this.scrollTimer_, goog.Timer.TICK,
    this.testScroller_, false, this);
                     
  goog.events.listen(this.Handler_.getWindowArea(),
    goog.events.EventType.SCROLL,
    this.onWindowScroll_, false, this);

  goog.events.listen(this.Handler_.getLeftEdge(), goog.ui.Component.EventType.ENTER, this.leftEdgeEnter_, false, this);
  goog.events.listen(this.Handler_.getLeftEdge(), goog.ui.Component.EventType.LEAVE, this.leftEdgeLeave_, false, this);
  
  goog.events.listen(this.Handler_.getRightEdge(), goog.ui.Component.EventType.ENTER, this.rightEdgeEnter_, false, this);
  goog.events.listen(this.Handler_.getRightEdge(), goog.ui.Component.EventType.LEAVE, this.rightEdgeLeave_, false, this);

  goog.events.listen(this.Handler_.getLeftEdge(), goog.ui.Component.EventType.ACTION, this.leftEdgeClicked_, false, this);
  goog.events.listen(this.Handler_.getRightEdge(), goog.ui.Component.EventType.ACTION, this.rightEdgeClicked_, false, this);
};


/**
 * Event handler that is used on mouse move.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onMouseMove_ = function(e) {
  this.XposNow_ = e.clientX;
};

georeferencer.slider.Dragger.prototype.leftEdgeEnter_ = function(e) {
  this.Handler_.getLeftEdge().addClassName("side-edge-hover");
  this.Handler_.getLeftButton().addClassName("left-button-hover");
};

georeferencer.slider.Dragger.prototype.leftEdgeLeave_ = function(e) {  
  this.Handler_.getLeftEdge().removeClassName("side-edge-hover");
  this.Handler_.getLeftButton().removeClassName("left-button-hover");
}

georeferencer.slider.Dragger.prototype.rightEdgeEnter_ = function(e) {  
  this.Handler_.getRightEdge().addClassName("side-edge-hover");
  this.Handler_.getRightButton().addClassName("right-button-hover");
};

georeferencer.slider.Dragger.prototype.rightEdgeLeave_ = function(e) {  
  this.Handler_.getRightEdge().removeClassName("side-edge-hover");
  this.Handler_.getRightButton().removeClassName("right-button-hover");
}


georeferencer.slider.Dragger.prototype.leftEdgeClicked_ = function(e) {
  this.easyShift_(-500);
};


georeferencer.slider.Dragger.prototype.rightEdgeClicked_ = function(e) {
  this.easyShift_(500);
};


/**
 * @private
 * @return {number} The x coordinate of the scroll offset coordinates.
 */
georeferencer.slider.Dragger.prototype.getScrollLeft_ = function() {  
  if (this.Handler_.getWindowArea()['scrollLeft'] > 0) {
    return this.Handler_.getWindowArea()['scrollLeft'];
  } else if (document.documentElement.scrollLeft > 0) {
    return document.documentElement.scrollLeft;
  } else if (document.body.scrollLeft > 0) {
    return document.body.scrollLeft;
  } else {
    return 0;
  }  
};


/**
 * @param {number} scrollLeftPosition Set the x coordinate of the scroll
 * offset coordinates.
 * @private
 */
georeferencer.slider.Dragger.prototype.setScrollLeft_ =
  function(scrollLeftPosition) {
    this.Handler_.getWindowArea()['scrollLeft'] = scrollLeftPosition;
    document.documentElement.scrollLeft = scrollLeftPosition;
    document.body.scrollLeft = scrollLeftPosition;
  };



georeferencer.slider.Dragger.prototype.onWindowScroll_ = function() {
  if(this.getScrollLeft_() < 2) {
    this.Handler_.getLeftEdge().setVisible(false);
  } else {
    this.Handler_.getLeftEdge().setVisible(true);
  }
  var scrollWidth = this.Handler_.getWindowArea()['scrollWidth'];
  var left = this.getScrollLeft_();
  var width = this.Handler_.getWindowArea()['clientWidth'];
  if(width + left + 2 > scrollWidth) {
    this.Handler_.getRightEdge().setVisible(false);
  } else {
    this.Handler_.getRightEdge().setVisible(true);
  }    
};



/**
 * @private
 */
georeferencer.slider.Dragger.prototype.testScroller_ = function() {
  var scrollLeftPosition = this.getScrollLeft_();
  var width = this.Handler_.getWindowArea()['scrollWidth'] -
  this.Handler_.getWindowArea()['clientWidth'];
  if (scrollLeftPosition > width * (7 / 8) &&
    !this.Handler_.isScrollLoading()) {
    this.Handler_.setScrollLoading(true);
    this.Handler_.getMoreImages();
    if (this.Handler_.noMoreImages()) {
      this.scrollTimer_.stop();
    }
  }
};


/**
 * @param {number} shiftLength The length of the shift.
 * @private
 */
georeferencer.slider.Dragger.prototype.easyShift_ = function(shiftLength) {  
  var scrollLeftPosition = this.getScrollLeft_();
  var anim = new goog.fx.Animation([scrollLeftPosition, 0],
    [scrollLeftPosition + shiftLength, 0],
    this.dealy_, goog.fx.easing.easeOut);
  goog.events.listen(anim, goog.fx.Animation.EventType.BEGIN, this.onAnimationBegin_, false, this);
  goog.events.listen(anim, goog.fx.Animation.EventType.ANIMATE, this.onAnimationAnimate_, false, this);
  goog.events.listen(anim, goog.fx.Animation.EventType.END, this.onAnimationEnd_, false, this);
  anim.play(false);  
};


/**
 * Event handler that is used on animation begin.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onAnimationBegin_ = function(e) {
  // console.log("anim begin");
  // this.Handler_.disableButtons();
  };


/**
 * Event handler that is used on animation animate.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onAnimationAnimate_ = function(e) {
  this.setScrollLeft_(e.x);
};


/**
 * Event handler that is used on animation end.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onAnimationEnd_ = function(e) {
  //console.log("anim stop");
  //this.Handler_.enableButtons();
  };






/**
 * Event handler that is used on drag.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onDrag_ = function(e) {
  this.dragging_ = true;
  this.setScrollLeft_(this.getScrollLeft_() + this.dragPosX_ - e.clientX);
  this.dragPosX_ = e.clientX;
};


/**
 * Event handler that is used on drag start.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onDragStart_ = function(e) {
  this.dragPosX_ = e.clientX;
};


/**
 * Event handler that is used on drag end.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onDragEnd_ = function(e) {
  this.endDragPosX_ = this.XposNow_;
  this.shiftTimer_.start();
};


/**
 * Event handler that is used on mouse down.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onMouseDown_ = function(e) {
  this.dragger_.startDrag(e);
};







/**
 * Event handler for shift timer.
 * @param {goog.events.BrowserEvent} e Event object.
 * @private
 */
georeferencer.slider.Dragger.prototype.onShiftTick_ = function(e) {
  var posDif = this.endDragPosX_ - this.XposNow_;
  var shiftSign = posDif == 0 ? 0 : (posDif < 0 ? -1 : 1);
  var shiftLength = Math.abs(posDif);
  this.shiftTimer_.stop();
  if (shiftLength > 10) {
    if (shiftLength < 50) {
      this.easyShift_(500 * shiftSign);
    } else if (shiftLength < 100) {
      this.easyShift_(1000 * shiftSign);
    } else {
      this.easyShift_(1500 * shiftSign);
    }
  }
  this.dragging_ = false;
};